﻿// ***************************************************************
//  property   version:  1.0   ·  date: 05/29/2010
//  -------------------------------------------------------------
//  属性集合
//  -------------------------------------------------------------
//  Copyright (C) 2010 - All Rights Reserved
// ***************************************************************
// 
// ***************************************************************
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
#pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)

#ifndef ccs_util_data_property_h__
#define ccs_util_data_property_h__

#include "ccs_util/data/variant.hpp"



namespace ccs
{
	/** 动态属性类型 */
	class property
	{
	public:

		/** @brief 默认构造函数
		一般情况下被property_set中的std::map调用，构造之后，并不包含任何数据，
		所以不能从property对象中取出数据，否则会出错。
		*/
		property();

		/** @brief 针对字符串常量的构造函数
		如果是字符串常量在初始阶段的赋值，那么内部会当做std::string类型做处理。
		@param  var 字符串常量指针
		@note 构造函数都有可能在赋值运算符重载 operator= 中被显式调用。
		@see property::operator = (const char var[])
		@see property::operator = (VarType const& var)
		*/
		property(char* const var);

		/** @brief 针对内部字符串数组的构造函数
		如果是内部字符串数组在初始阶段的赋值，那么内部会当做std::string类型做处理。
		@param  var 内部字符串数组名
		@code
		props["name"] = "Shanoa";
		@note 构造函数都有可能在赋值运算符重载 operator= 中被显式调用。
		@see property::operator = (const char var[])
		@see property::operator = (VarType const& var)
		*/
		property(const char var[]);

		/** @brief 分离类型的构造函数
		@param var 可以是任何类型的对象。
		@note 构造函数都有可能在赋值运算符重载 operator= 中被显式调用。
		@see property::operator = (const char var[])
		@see property::operator = (VarType const& var)
		*/
		template<typename VarType>
		property(VarType const& var);

		/** @brief 赋值运算符重载
		内部通过显式调用构造函数来对property对象进行赋值操作。
		@return 返回的是property对象本身。
		@param var 用户传递进来的任意类型的值或对象。
		*/
		template<typename VarType>
		property& operator = (VarType const& var);

		/** @brief 隐式转换对象类型的运算符重载

		@return 返回数据类型的对象，该对象的类型就是用户传入该属性的类型
		*/
		template<typename VarType>
		operator VarType const&() const;

		event::connection observe(std::string const& eventName, event::slot2 const& handler)
		{
			return data_->observe(eventName, handler);
		}

		bool is_self_event() const { return data_->is_self_event(); }

	protected:

		/** @brief 编译期分离函数，将值存储进property对象中。
		利用模板技术进行编译期的分离处理，由构造函数进行调用，进入该函数的VarType
		将会是C++内部类型，该类型可以更高效的进行存取操作。
		@param var 即将存入property的C++内部类型对象。
		@see property::property(VarType const& var)
		*/
		template<typename VarType>
		void split_assign_variant(VarType const& var, boost::true_type const&);

		/** @brief 编译期分离函数，将值存储进property对象中。
		利用模板技术进行编译期的分离处理，由构造函数进行调用，进入该函数的VarType
		将会是自定义的类型，这种类型必须拥有合法的拷贝构造函数。
		@param var 即将存入property的自定义类型的对象，必须可拷贝。
		@see property::property(VarType const& var)
		*/
		template<typename VarType>
		void split_assign_variant(VarType const& var, boost::false_type const&);

		/** @brief 编译器分离函数，从property中获取数据对象。
		利用模板技术进行编译期的分离处理，会由隐式类型转换运算符重载调用。
		@return 返回C++内部类型值
		@see property::operator VarType const&()
		*/
		template<typename VarType>
		VarType const& split_query_variant(boost::true_type const&) const;

		/** @brief 编译器分离函数，从property中获取数据对象。
		利用模板技术进行编译期的分离处理，会由隐式类型转换运算符重载调用。
		@return 返回自定义类型对象的引用
		@see property::operator VarType const&()
		*/
		template<typename VarType>
		VarType const& split_query_variant(boost::false_type const&) const;

		any_data_ptr data_;
	};

	/** 动态属性集合 */
	class property_set
	{
	public:
		property_set() {}
		property const& get_property(std::string const& propName) const;
		property const& add_property(std::string const& propName, property const& propVar);
		//property const& operator[](std::string const& propName) const;
		//property& operator[](std::string const& propName);
		bool has(std::string const& propName);

		template<typename VarType>
		void set_property(std::string const& propName, VarType const& propVar)
		{
			property_nested& propNested = get_property_nested(propName);

			VarType oldVar = propNested.prop_;
			propNested.prop_ = propVar;

			std::streambuf sbuf;
			oarchive(sbuf) << propVar << oldVar;
			(*propNested.signal_)(propName, iarchive(sbuf));
		}

		event::connection observe_property(std::string const& propName, std::string const& eventName, event::slot2 const& handler)
		{
			property_nested& propNested = get_property_nested(propName);
			if (propNested.prop_.is_self_event())
			{
				propNested.prop_.observe(eventName, handler);
			}
			else if (eventName == "ValueChangedEvent")
			{
				return get_property_nested(propName).signal_->connect(handler);
			}
			else
			{
				// exception
			}
		}

	protected:

	private:
		struct property_nested
		{
			property_nested(property const& prop): prop_(prop){}
			property prop_;
			boost::shared_ptr<event::signal2> signal_;
		};

		property_nested& get_property_nested(std::string const& propName)
		{
			prop_map::iterator it = props_.find(propName);
			if (it == props_.end())
			{
				std::ostringstream oss;
				oss<<"不存在属性："<<propName;
				throw std::exception(oss.str().c_str());
			}
			return it->second;
		}

		property_nested const& get_property_nested(std::string const& propName) const
		{
			prop_map::const_iterator it = props_.find(propName);
			if (it == props_.end())
			{
				std::ostringstream oss;
				oss<<"不存在属性："<<propName;
				throw std::exception(oss.str().c_str());
			}
			return it->second;
		}

		
		typedef std::map<std::string, property_nested> prop_map;
		prop_map props_;
	};
}

#endif /*ccs_util_data_property_h__*/